package com.gaussian.property.app.controller;

import cn.hutool.core.date.DateTime;
import cn.hutool.core.date.DateUnit;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.io.FileTypeUtil;
import cn.hutool.http.HttpRequest;
import cn.hutool.http.HttpResponse;
import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import com.aliyun.oss.OSS;
import com.aliyun.oss.OSSClientBuilder;
import com.aliyun.oss.model.OSSObject;
import com.aliyun.oss.model.ObjectMetadata;
import com.aliyun.oss.model.PutObjectRequest;
import com.gaussian.property.module.biz.vo.oss.DocSnapshot;
import com.gaussian.property.module.biz.vo.oss.OssConfig;
import com.gaussian.property.module.biz.vo.oss.OssReqeust;
import com.songqi.common.core.constant.HttpStatus;
import com.songqi.common.core.domain.R;
import com.songqi.common.core.exception.CustomException;
import com.songqi.common.core.utils.sign.Md5Utils;
import com.songqi.common.core.utils.sign.ShaUtil;
import com.songqi.common.core.utils.uuid.UUID;
import com.songqi.common.redis.RedisUtils;
import com.songqi.common.web.request.controller.BaseController;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import io.swagger.annotations.ApiParam;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletResponse;
import javax.validation.constraints.NotBlank;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.security.NoSuchAlgorithmException;
import java.util.Date;
import java.util.TimeZone;
import java.util.concurrent.TimeUnit;

/**
 * 通用请求处理
 *
 * @author songqi(13776346982)
 */
@Api(tags = "文件、图片操作")
@RestController
@RequestMapping("common/")
@Validated
public class CommonController extends BaseController {

    @Value("${gaussian.api.ossSign}")
    private String ossSignUrl;


    @Resource
    private RedisUtils redisUtils;
/*

   @Resource
    private OssClient ossClient;



    @ApiOperation("S3协议文件上传")
    @PostMapping(value = "s3/upload")
    public R<String> uploadObject(@RequestPart MultipartFile file,
                                  @ApiParam("oss存储目录。如/image/") @RequestParam String dir,
                                  @ApiParam("oss存储空间。")  @RequestParam(required = false) String bucket) {
        String result = "";
        try {
            result = ossClient.upload(bucket, dir, file);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return R.success(result);
    }
*/

    @ApiOperation("(停用)oss文件上传，返回文件在oss服务器上的存储路径")
    @PostMapping(value = "ossUpload")
    @Deprecated
    public R<String> ossUpload(@RequestHeader("Authorization") String authorization,
                               @RequestHeader("Front-Request-Id") String frontRequestId,
                               @RequestHeader("Ics-Authorization") String icsAuthorization,
                               @RequestHeader("Admission") String admission,
                               @RequestPart MultipartFile file) {

        OssConfig ossConfig = getOssConfig(authorization, frontRequestId, icsAuthorization, admission);
        if(ossConfig != null){
            String accessKeyId = ossConfig.getAccessKeyId();
            String accessKeySecret = ossConfig.getAccessKeySecret();
            String securityToken = ossConfig.getSecurityToken();
            String endPoint = ossConfig.getEndPoint();
            String bucket = ossConfig.getBucket();
            OSS ossClient = new OSSClientBuilder().build(endPoint, accessKeyId, accessKeySecret, securityToken);
            if(ossClient != null){
                try {
                    String fileType = FileTypeUtil.getType(file.getInputStream());
                    String objectName = "property/" + fileType + "/" + UUID.fastUUID() + file.getOriginalFilename();
                    ObjectMetadata metadata = new ObjectMetadata();
                    metadata.setContentType(file.getContentType());
                    PutObjectRequest request = new PutObjectRequest(bucket, objectName, file.getInputStream(), metadata);
                    ossClient.putObject(request);
                    return R.success(objectName);
                } catch (Exception e){
                    throw new CustomException("oss文件上传失败。请重试");
                } finally {
                    ossClient.shutdown();
                }
            }
        }
        return R.error("文件上传失败");
    }


    @ApiOperation("(前端传OssToken)根据文件在oss服务器上的存储路径返回访问url")
    @PostMapping("genOssFileUrl")
    public R<String> ossFileUrl(@RequestBody OssConfig ossConfig){
        String url = OssConfig.getOssFileUrl(ossConfig.getObjectFileName(), ossConfig);
        if (url != null){
            return R.success(url);
        }
        return R.error("生成文件url失败");
    }


    @ApiOperation("oss文件快照")
    @PostMapping("docSnapshot")
    public void docSnapshot(@RequestBody DocSnapshot docSnapshot, HttpServletResponse response) throws IOException {
        OutputStream outputStream = getPreviewOutputStream(response, "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");
        OssConfig.docSnapshot(docSnapshot, outputStream);
    }


    @ApiOperation("(前端不传OssToken)根据文件在oss服务器上的存储路径返回访问url")
    @GetMapping(value = "ossFileUrl")
    public R<String> ossFileUrl(@RequestHeader("Authorization") String authorization,
                                @RequestHeader("Front-Request-Id") String frontRequestId,
                                @RequestHeader("Ics-Authorization") String icsAuthorization,
                                @RequestHeader("Admission") String admission,
                                @ApiParam("文件在oss服务器上的存储路径") @NotBlank(message = "文件在oss服务器上的存储路径不能为空") String fileObjectName){
        OssConfig ossConfig = getOssConfig(authorization, frontRequestId, icsAuthorization, admission);
        String url = OssConfig.getOssFileUrl(fileObjectName, ossConfig);
        if (url != null){
            return R.success(url);
        }
        return R.error("生成文件url失败");
    }




    @ApiOperation("oss文件预览")
    @GetMapping(value = "ossPreview")
    public void ossPreview(@RequestHeader("Authorization") String authorization,
                             @RequestHeader("Front-Request-Id") String frontRequestId,
                             @RequestHeader("Ics-Authorization") String icsAuthorization,
                             @RequestHeader("Admission") String admission,
                             @ApiParam("文件在oss服务器上的存储路径") @NotBlank(message = "文件在oss服务器上的存储路径不能为空") String fileObjectName,
                             HttpServletResponse response){
        OssConfig ossConfig = getOssConfig(authorization, frontRequestId, icsAuthorization, admission);
        if(ossConfig != null){
            String accessKeyId = ossConfig.getAccessKeyId();
            String accessKeySecret = ossConfig.getAccessKeySecret();
            String securityToken = ossConfig.getSecurityToken();
            String endPoint = ossConfig.getEndPoint();
            String bucket = ossConfig.getBucket();
            OSS ossClient = new OSSClientBuilder().build(endPoint, accessKeyId, accessKeySecret, securityToken);
            if(ossClient != null){
                try {
                    OSSObject ossObject = ossClient.getObject(bucket, fileObjectName);
                    InputStream inputStream = ossObject.getObjectContent();
                    ObjectMetadata objectMetadata = ossObject.getObjectMetadata();
                    String contentType = objectMetadata.getContentType();
                    preview(response, contentType, inputStream);
                } catch (Exception e){
                    throw new CustomException("oss文件上传失败。请重试");
                } finally {
                    ossClient.shutdown();
                }
            }
        }

    }







    private OssConfig getOssConfig(String authorization, String frontRequestId, String icsAuthorization, String admission){
        String ossConfigKey = "gaussian.ossConfig";
        OssConfig ossConfig = null;
        logger.info("调用高仙{}请求参数：Authorization={}, Front-Request-Id={}, Ics-Authorization={}, Admission={}",
                ossSignUrl, authorization, frontRequestId, icsAuthorization, admission);
        HttpResponse response = HttpRequest.get(ossSignUrl)
                .header("Authorization", authorization)
                .header("Front-Request-Id", frontRequestId)
                .header("Ics-Authorization", icsAuthorization)
                .header("Admission", admission).execute();
        if(response.isOk()){
            String respBody = response.body();
            logger.info("调用高仙{}返回结果：{}", ossSignUrl, respBody);
            R r = JSONUtil.toBean(respBody, R.class);
            if(r.getCode() == HttpStatus.SUCCESS){
                // 解析数据
                JSONObject jsonObject = (JSONObject) r.getData();
                ossConfig =  jsonObject.toBean(OssConfig.class);
                String expiration = ossConfig.getExpiration();
                DateTime dateTime = DateUtil.parse(expiration).setTimeZone(TimeZone.getTimeZone("Asia/Shanghai"));
                long diff = DateUtil.between(new Date(), dateTime, DateUnit.SECOND);
                redisUtils.setCacheObject(ossConfigKey, ossConfig, diff-5, TimeUnit.SECONDS);
            }else{
                logger.error("调用高仙{}失败。失败信息：{}", ossSignUrl, r.getMsg());
                throw new CustomException("查询oss参数失败。错误原因：" + r.getMsg());
            }
        } else {
            logger.error("连接超时");
            throw new CustomException("调用高仙接口发生异常");
        }

        return ossConfig;

    }

}
